import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;


public class Sheriff implements Actor{
	
	// Characteristics shared by all foxes (static fields).
    // The Hunter that the Sheriff is currently hunting
    private Hunter iHuntThis;
    // A list of hunters that are currently on the entire fieldview.
    private ArrayList<Hunter> hunters = new ArrayList<Hunter>();
    
    // Whether the animal is alive or not.
    private boolean active;
    // The animal's field.
    private Field field;
    // The animal's position in the field.
    private Location location;
    
    
    /**
     * Create a sheriff. A sheriff can be created as a new born (age zero)
     *  or with a random age and food level.
     * 
     * @param field The field currently occupied.
     * @param location The location within the field.
     * 
     */
    public Sheriff (boolean randomAge, Field field, Location location)
    {
    	active = true;
        this.field = field;
        setLocation(location);
    }
    
    /**
     * This is what a sheriff does most of the time. He acts out a daily routine.
     * @param field The field currently occupied.
     * @param Deputies A list to add newly born little deputies to.
     */
    public void act(List<Actor> newSheriffs)
    {
        if(isActive()) {
        	fillHunters();
        	//a few if statements to find a new hunter for this sheriff to hunt. If he found a hunter set it to hunted
        	findNewHunter();
            // Go and kill a hunter if a hunter is within earshot.
            Location location = getLocation();
            Location newLocation = catchHunter(location);
            //however if he is not:
            if(newLocation == null) { 
                // Get closer to the set hunter.
            	if(iHuntThis.getLocation() != null){
                newLocation = getDirectionHunter(location);
                	if(newLocation == null){
                	newLocation = getAlternativePath(location);
                	}
            	}
            }
            // See if it was possible to move.
            if(newLocation != null) {
                setLocation(newLocation);
            }
            else {
                // Nothing to hunt... time to leave!
            	if(iHuntThis != null){
            		iHuntThis.unsetHunted();
            	}
                setDead();
            }
        }
    }

    /**
     * a few checks to find a new hunter. When the sheriff has found a hunter he will set it as a target.
     */
    private void findNewHunter(){
        if(iHuntThis == null || iHuntThis.getLocation() == null || !iHuntThis.isActive()){
        	findHunter(); 
        		if(iHuntThis != null){
        			iHuntThis.setHunted();
        			}
        }
    }
    /**
     * checks if the prey is viable for hunting.
     */
    
    private boolean viablePrey(Hunter hunter){
    	if(hunter.isActive() && !hunter.isHunted()){
    		return true;
    	}
    	return false;
    }
        
    /**
     * Tells the sheriff to look around its location for a hunter.
     * If there is a live hunter it will be killed.
     * @param location Where in the field it is located.
     * @return Where hunter was found, or null if it wasn't.
     */
    private Location catchHunter(Location location)
    {
        Field field = getField();
        List<Location> adjacent = field.adjacentLocations(getLocation());
        Iterator<Location> it = adjacent.iterator();
        while(it.hasNext()) {
            Location where = it.next();
            Object animal = field.getObjectAt(where);
            if(animal instanceof Hunter) {
              Hunter hunter = (Hunter) animal;
                if(hunter.isActive()) { 
                    hunter.setInactive();
                    return where;
                }
            }

       }		
       return null;
   }
    
    
    /**
     * Goes through the entire field and fills an arraylist with that information.
     */
    private void fillHunters(){
    	hunters.clear();
    	Field field = this.getField();
		int depth = field.getDepth();
		int width = field.getWidth();
    	for(int x = 0; depth>x; x++)
    	{
    		for(int y = 0; width>y; y++)
    		{
    		Object hunter = field.getObjectAt(x, y);
    			if(hunter instanceof Hunter){
    				Hunter realhunter = (Hunter) hunter;
    				if(viablePrey(realhunter)){
    				hunters.add(realhunter);
    				}

    			}
    		}
    	}
    }
    
   // private void pickUp(Animal animal)
   // 	{
   // 	
   // 	}
    /**
     * returns the ints of your current location and 
     * @param myLocation
     * @param hunterLocation
     * @return
     */
    private int[] getLocationData(Location myLocation, Location hunterLocation){
    	int[] returnwaarden = new int[4];
    	
    	int hrow = hunterLocation.getRow();
    	int hcol = hunterLocation.getCol();
    	int mrow = myLocation.getRow();
    	int mcol = myLocation.getCol();
    	int drow = hrow - mrow;
    	int dcol = hcol - mcol;
    	
    	int richting = 0;
    	if(drow>0){richting=1;/*beneden*/ mrow++ ;}
    	if(drow<0){richting=1;/*boven*/ mrow-- ;}
    	if(dcol>0){richting=1;/*right*/ mcol++ ;}
    	if(dcol<0){richting=1;/*left*/ mcol-- ;}
    	if(drow<0){drow = drow * -1;}
    	if(dcol<0){dcol = dcol * -1;}
    	int davg = drow + dcol;
    	
    	returnwaarden[0] = mrow;
    	returnwaarden[1] = mcol;
    	returnwaarden[2] = davg;
    	returnwaarden[3] = richting;
    	return returnwaarden;
    }
    
    /**
     * gets the general direction of the hunter and goes the tile closest to that direction
     * @param myLocation
     * @return possLocation a location that is possible the location to go to.
     */
    private Location getDirectionHunter(Location myLocation)
    	{
        Location hunterLocation = iHuntThis.getLocation();
    	int[] locationData = getLocationData(myLocation, hunterLocation);
    	int mrow = locationData[0];
    	int mcol = locationData[1];
    	int richting = locationData[3];
    	
    	Field field = this.getField();
    	if(richting>0)
    	{
    		Object obj = field.getObjectAt(mrow, mcol);
    		if(obj instanceof Animal){
    			Animal anAnimal = (Animal)field.getObjectAt(mrow, mcol);
    			Location newLocation = anAnimal.getLocation();
    			anAnimal.setDead();
    			return newLocation;
    		}else{
    			List<Location> adjacent = field.adjacentLocations(myLocation);
    			Iterator<Location> it = adjacent.iterator();
    			Location possLocation = null;
    				while(it.hasNext()){
    					possLocation = it.next(); 
    					if(possLocation.getCol() == mcol && possLocation.getRow() == mrow){
    						return possLocation;
    					}
    				}
    		}
    	}
    	
    	return null;
    	
    	
    }  
    /**
     * Finds a random alternative location to go to.
     */
    private Location getAlternativePath(Location myLocation){
    	Field field = this.getField();
    	List<Location> adjacent = field.adjacentLocations(this.getLocation());
    	Iterator<Location> it = adjacent.iterator();
    	Location newLocation = null;
    	while(it.hasNext()){
    		Location check = it.next();
    		Object obj = field.getObjectAt(check);
    		if(obj == null){
    			return check;
    		}
    		if(obj instanceof Animal){
    			Animal anAnimal = (Animal)field.getObjectAt(check);
    			anAnimal.setDead();
    			return check;
    		}
    	}
    	return newLocation;
    }
    /**
     * Sets a hunter as being hunted and set that hunter as a target for this sheriff.
     */
    private void findHunter(){
    
    Field field = getField();
    Location myLocation = getLocation();
    Location hunterLocation;
    int[] newarray = new int[4];
    int distance = field.getDepth() + field.getWidth(); 
    int deviation = 0;
    	for(int x = 0;hunters.size()>x;x++)
    	{
    		Hunter huntr = hunters.get(x);
    		if(!huntr.isHunted() && huntr.isActive()){
    			hunterLocation = huntr.getLocation();
    			newarray = getLocationData(myLocation, hunterLocation);
    			deviation = newarray[2];
    				if(deviation<distance&&deviation>0)
    				{
    				iHuntThis = huntr;
    				distance = deviation;
    				}
    			
    			}
    	}
    }
    
    /**
     * Check whether the animal is alive or not.
     * @return true if the animal is still alive.
     */
    public boolean isActive()
    {
        return active;
    }

    /**
     * Indicate that the animal is no longer alive.
     * It is removed from the field.
     */
    public void setDead()
    {
        active = false;
        if(location != null) {
            field.clear(location);
            location = null;
            field = null;
        }
    }

    /**
     * Return the animal's location.
     * @return The animal's location.
     */
    public Location getLocation()
    {
        return location;
    }
    
    /**
     * Return the animal's field.
     * @return The animal's field.
     */
    public Field getField()
    {
        return field;
    }
    
    /**
     * Place the animal at the new location in the given field.
     * @param newLocation The animal's new location.
     */
    public void setLocation(Location newLocation)
    {
        if(location != null) {
            field.clear(location);
        }
        
        location = newLocation;
        field.place(this, newLocation);
    }
    
}